import * as THREE from 'three'

/**
 * 物理模拟器 - 实现力导向布局算法
 */
export class Simulator {
  constructor(renderer, graph) {
    this.renderer = renderer
    this.graph = graph
    
    // 模拟参数
    this.kValue = 100 // 弹簧常数
    this.damping = 0.9 // 阻尼
    this.timeStep = 0.016 // 时间步长
    
    // 力导向算法参数
    this.attractionForce = 0.1
    this.repulsionForce = 1000
    this.centeringForce = 0.01
    
    // 节点状态
    this.positions = null
    this.velocities = null
    this.forces = null
    this.nodeCount = 0
    
    // 边数据
    this.edgeIndices = null
    this.edgeCount = 0
    
    // 布局模式
    this.layoutMode = 'force'
    
    // 时间过滤
    this.timeMin = 0
    this.timeMax = Number.MAX_SAFE_INTEGER
  }

  /**
   * 初始化模拟器
   */
  init() {
    this.setupNodeData()
    this.setupEdgeData()
    this.initializePositions()
    this.initializeVelocities()
    this.initializeForces()
    
    console.log(`[${new Date().toLocaleTimeString()}] 模拟器初始化完成: ${this.nodeCount} 节点, ${this.edgeCount} 边`)
  }

  /**
   * 设置节点数据
   */
  setupNodeData() {
    const nodes = Object.values(this.graph.nodes).sort((a, b) => a.id - b.id)
    this.nodeCount = nodes.length
    
    if (this.nodeCount === 0) {
      console.warn('没有节点数据')
      return
    }
  }

  /**
   * 设置边数据
   */
  setupEdgeData() {
    const edges = Object.values(this.graph.edges)
    const nodes = this.graph.nodes
    
    const validEdges = []
    
    edges.forEach(edge => {
      const sourceNode = nodes[edge.source]
      const targetNode = nodes[edge.target]
      
      if (sourceNode && targetNode) {
        validEdges.push([sourceNode.id, targetNode.id])
      }
    })
    
    this.edgeIndices = new Int32Array(validEdges.length * 2)
    this.edgeCount = validEdges.length
    
    validEdges.forEach((edge, index) => {
      this.edgeIndices[index * 2] = edge[0]
      this.edgeIndices[index * 2 + 1] = edge[1]
    })
  }

  /**
   * 初始化位置
   */
  initializePositions() {
    this.positions = new Float32Array(this.nodeCount * 3)
    
    for (let i = 0; i < this.nodeCount; i++) {
      this.positions[i * 3] = (Math.random() - 0.5) * 1000
      this.positions[i * 3 + 1] = (Math.random() - 0.5) * 1000
      this.positions[i * 3 + 2] = (Math.random() - 0.5) * 1000
    }
  }

  /**
   * 初始化速度
   */
  initializeVelocities() {
    this.velocities = new Float32Array(this.nodeCount * 3)
    // 初始速度为0
  }

  /**
   * 初始化力
   */
  initializeForces() {
    this.forces = new Float32Array(this.nodeCount * 3)
  }

  /**
   * 更新模拟
   */
  update(deltaTime, temperature = 1.0) {
    if (this.layoutMode !== 'force' || this.nodeCount === 0) return
    
    this.clearForces()
    this.calculateForces(temperature)
    this.integrate(deltaTime)
  }

  /**
   * 清空力
   */
  clearForces() {
    for (let i = 0; i < this.forces.length; i++) {
      this.forces[i] = 0
    }
  }

  /**
   * 计算力
   */
  calculateForces(temperature) {
    // 斥力（所有节点之间）
    this.calculateRepulsionForces()
    
    // 引力（连接的节点之间）
    this.calculateAttractionForces()
    
    // 居中力
    this.calculateCenteringForces()
    
    // 应用温度
    this.applyTemperature(temperature)
  }

  /**
   * 计算斥力
   */
  calculateRepulsionForces() {
    for (let i = 0; i < this.nodeCount; i++) {
      for (let j = i + 1; j < this.nodeCount; j++) {
        const dx = this.positions[i * 3] - this.positions[j * 3]
        const dy = this.positions[i * 3 + 1] - this.positions[j * 3 + 1]
        const dz = this.positions[i * 3 + 2] - this.positions[j * 3 + 2]
        
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz)
        if (distance === 0) continue
        
        const force = this.repulsionForce / (distance * distance)
        const fx = (dx / distance) * force
        const fy = (dy / distance) * force
        const fz = (dz / distance) * force
        
        this.forces[i * 3] += fx
        this.forces[i * 3 + 1] += fy
        this.forces[i * 3 + 2] += fz
        
        this.forces[j * 3] -= fx
        this.forces[j * 3 + 1] -= fy
        this.forces[j * 3 + 2] -= fz
      }
    }
  }

  /**
   * 计算引力
   */
  calculateAttractionForces() {
    for (let i = 0; i < this.edgeCount; i++) {
      const nodeA = this.edgeIndices[i * 2]
      const nodeB = this.edgeIndices[i * 2 + 1]
      
      if (nodeA >= this.nodeCount || nodeB >= this.nodeCount) continue
      
      const dx = this.positions[nodeB * 3] - this.positions[nodeA * 3]
      const dy = this.positions[nodeB * 3 + 1] - this.positions[nodeA * 3 + 1]
      const dz = this.positions[nodeB * 3 + 2] - this.positions[nodeA * 3 + 2]
      
      const distance = Math.sqrt(dx * dx + dy * dy + dz * dz)
      if (distance === 0) continue
      
      const force = this.attractionForce * (distance - this.kValue)
      const fx = (dx / distance) * force
      const fy = (dy / distance) * force
      const fz = (dz / distance) * force
      
      this.forces[nodeA * 3] += fx
      this.forces[nodeA * 3 + 1] += fy
      this.forces[nodeA * 3 + 2] += fz
      
      this.forces[nodeB * 3] -= fx
      this.forces[nodeB * 3 + 1] -= fy
      this.forces[nodeB * 3 + 2] -= fz
    }
  }

  /**
   * 计算居中力
   */
  calculateCenteringForces() {
    for (let i = 0; i < this.nodeCount; i++) {
      this.forces[i * 3] -= this.positions[i * 3] * this.centeringForce
      this.forces[i * 3 + 1] -= this.positions[i * 3 + 1] * this.centeringForce
      this.forces[i * 3 + 2] -= this.positions[i * 3 + 2] * this.centeringForce
    }
  }

  /**
   * 应用温度
   */
  applyTemperature(temperature) {
    const tempFactor = temperature / 100
    for (let i = 0; i < this.forces.length; i++) {
      this.forces[i] *= tempFactor
    }
  }

  /**
   * 积分器
   */
  integrate(deltaTime) {
    for (let i = 0; i < this.nodeCount; i++) {
      // 更新速度
      this.velocities[i * 3] = this.velocities[i * 3] * this.damping + this.forces[i * 3] * deltaTime
      this.velocities[i * 3 + 1] = this.velocities[i * 3 + 1] * this.damping + this.forces[i * 3 + 1] * deltaTime
      this.velocities[i * 3 + 2] = this.velocities[i * 3 + 2] * this.damping + this.forces[i * 3 + 2] * deltaTime
      
      // 更新位置
      this.positions[i * 3] += this.velocities[i * 3] * deltaTime
      this.positions[i * 3 + 1] += this.velocities[i * 3 + 1] * deltaTime
      this.positions[i * 3 + 2] += this.velocities[i * 3 + 2] * deltaTime
    }
  }

  /**
   * 获取位置数组
   */
  getPositions() {
    return this.positions
  }

  /**
   * 设置K值
   */
  setKValue(value) {
    this.kValue = value
  }

  /**
   * 设置布局模式
   */
  setLayoutMode(mode) {
    this.layoutMode = mode
  }

  /**
   * 设置时间范围
   */
  setTimeRange(min, max) {
    this.timeMin = min
    this.timeMax = max
  }

  /**
   * 重置模拟
   */
  reset() {
    this.initializePositions()
    this.initializeVelocities()
    this.initializeForces()
  }

  /**
   * 从几何体同步当前位置
   */
  syncPositionsFromGeometry(positionArray) {
    if (!this.positions || !positionArray) return
    
    const count = Math.min(this.positions.length, positionArray.length)
    for (let i = 0; i < count; i++) {
      this.positions[i] = positionArray[i]
    }
    
    // 重置速度，避免突然的跳跃
    this.initializeVelocities()
    this.initializeForces()
  }

  /**
   * 设置位置数据
   */
  setPositions(positions) {
    if (!positions || positions.length !== this.nodeCount * 3) return
    
    this.positions = new Float32Array(positions)
    this.initializeVelocities()
    this.initializeForces()
  }
}
